/**
 *  BasicBlockFinder.java : IceBird project
 *  19:51:41 
 */
package icebird.compiler.bytecode;

import java.util.TreeMap;

import icebird.metadata.BasicType;
import icebird.metadata.ExceptionEntry;
import icebird.metadata.Method;
import icebird.metadata.ReferenceType;
import icebird.metadata.constpool.ConstClass;
import icebird.metadata.constpool.ConstField;
import icebird.metadata.constpool.ConstIMethod;
import icebird.metadata.constpool.ConstMethod;

/**
 * @author Sergey Shulepoff[Knott]
 */
public class BasicBlockFinder extends BytecodeVisitor implements BytecodeFlags {
	
	private boolean nextBB;
	private boolean nextTS;
	
	private int address;
	
	private TypeStack ts;
	
	private BasicBlock current;
	private Method method;
	
	private TreeMap<Integer, BasicBlock> blocks;
	
	private byte[] opcodeFlags;
	
	
	public byte[] getOpcodeFlags() {
		return opcodeFlags;
	}
	
	/**
	 * 
	 */
	public BasicBlockFinder() {
		ts = new TypeStack();
		blocks = new TreeMap<Integer, BasicBlock>();
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#endInstruction()
	 */
	@Override
	public void endInstruction() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#endMethod()
	 */
	@Override
	public void endMethod() {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#startInstruction(int, byte)
	 */
	@Override
	public void startInstruction(int pc, byte opcode) {
		if (method == null) return;
		
		address = pc;
		opcodeFlags[pc] |= INSTRUCTION;
		
		if (nextBB) {
			startBB(pc, nextTS, ts);
			nextBB = false;
			nextTS = true;
		}
		
		if (isStartOfBB(pc)) {
			current = blocks.get(new Integer(pc));
			TypeStack bts = current.getEntryStack();
			if (ts != null) {
				ts = new TypeStack(bts);
			} else if (!nextTS) {
				ts.clear();
			} else {
				current.setEntryStack(ts);
			}
		}
	}
	
	public BasicBlock[] createBasicBlocks() {
		// Create the array		
		final BasicBlock[] list = blocks.values().toArray(new BasicBlock[blocks.size()]);
		// Set the EndPC's and flags
		final byte[] opcodeFlags = this.opcodeFlags;
		final int len = opcodeFlags.length;
		int bbIndex = 0;
		for (int i = 0; i < len; i++) {
			if (isStartOfBB(i)) {
				final int start = i;
				// Find the end of the BB
				i++;
				while ((i < len) && (!isStartOfBB(i))) {
					i++;
				}
				// the BB
				final BasicBlock bb = list[bbIndex++];
				if (bb.getStartPC() != start) {
					throw new AssertionError("bb.getStartPC() != start");
				}
				bb.setEndPC(i);
				bb.setException(isStartOfException(start));
				i--;
			}
		}
		if (bbIndex != list.length) {
			throw new AssertionError("bbIndex != list.length");
		}
		return list;
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#startMethod(icebird.metadata.Method)
	 */
	@Override
	public boolean startMethod(Method method) {
		this.method = method;
		
		ByteCode bc = new ByteCode(method);
		int length = bc.getLength();
		
		opcodeFlags = new byte[length];
		startBB(0, true, ts);
		
		TypeStack exts = new TypeStack();
		exts.push(new ReferenceType(null));
		for (ExceptionEntry e : bc.getExceptions()) {
			startTryBlock(e.getStartPC());
			startTryBlockEnd(e.getEndPC());
			startException(e.getHandlerPC(), exts);
		}
		
		return true;
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_aaload()
	 */
	@Override
	public void visit_aaload() {
		ts.pop(BasicType.Int);
		ts.pop(new ReferenceType(null));
		
		ts.push(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_aastore()
	 */
	@Override
	public void visit_aastore() {
		ts.pop(new ReferenceType(null));
		ts.pop(BasicType.Int);
		ts.pop(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_aconst_null()
	 */
	@Override
	public void visit_aconst_null() {
		ts.push(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_aload(int)
	 */
	@Override
	public void visit_aload(int index) {
		ts.push(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_anewarray(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_anewarray(ConstClass clazz) {
		ts.pop(BasicType.Int);
		ts.push(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_areturn()
	 */
	@Override
	public void visit_areturn() {
		ts.pop(new ReferenceType(null));
		endBB(false);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_arraylength()
	 */
	@Override
	public void visit_arraylength() {
		ts.pop(new ReferenceType(null));
		ts.push(BasicType.Int);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_astore(int)
	 */
	@Override
	public void visit_astore(int index) {
		ts.pop(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_athrow()
	 */
	@Override
	public void visit_athrow() {
		ts.pop(new ReferenceType(null));
		endBB(false);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_baload()
	 */
	@Override
	public void visit_baload() {
		ts.pop(BasicType.Int);
		ts.pop(new ReferenceType(null));

		ts.push(BasicType.Int);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_bastore()
	 */
	@Override
	public void visit_bastore() {
        ts.pop(BasicType.Int);
        ts.pop(BasicType.Int);
        ts.pop(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_caload()
	 */
	@Override
	public void visit_caload() {
		ts.pop(BasicType.Int);
		ts.pop(new ReferenceType(null));

		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_castore()
	 */
	@Override
	public void visit_castore() {
		ts.pop(BasicType.Int);
        ts.pop(BasicType.Int);
        ts.pop(new ReferenceType(null));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_checkcast(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_checkcast(ConstClass clazz) {
		ts.pop(new ReferenceType(null));
		ts.push(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_d2f()
	 */
	@Override
	public void visit_d2f() {
		ts.pop(BasicType.Double);
		ts.push(BasicType.Float);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_d2i()
	 */
	@Override
	public void visit_d2i() {
		ts.pop(BasicType.Double);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_d2l()
	 */
	@Override
	public void visit_d2l() {
		ts.pop(BasicType.Double);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dadd()
	 */
	@Override
	public void visit_dadd() {
		ts.pop(BasicType.Double);
		ts.pop(BasicType.Double);
		ts.push(BasicType.Double);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_daload()
	 */
	@Override
	public void visit_daload() {
		ts.pop(BasicType.Int);
		ts.pop(new ReferenceType(null));

		ts.push(BasicType.Double);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dastore()
	 */
	@Override
	public void visit_dastore() {
		ts.pop(BasicType.Double);
        ts.pop(BasicType.Int);
        ts.pop(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dcmpg()
	 */
	@Override
	public void visit_dcmpg() {
		ts.pop(BasicType.Double);
		ts.pop(BasicType.Double);
		
		ts.push(BasicType.Int);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dcmpl()
	 */
	@Override
	public void visit_dcmpl() {
		ts.pop(BasicType.Double);
		ts.pop(BasicType.Double);
		
		ts.push(BasicType.Int);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dconst(double)
	 */
	@Override
	public void visit_dconst(double value) {
		ts.push(BasicType.Double);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ddiv()
	 */
	@Override
	public void visit_ddiv() {
		ts.pop(BasicType.Double);
		ts.pop(BasicType.Double);
		ts.push(BasicType.Double);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dload(int)
	 */
	@Override
	public void visit_dload(int index) {
		ts.push(BasicType.Double);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dmul()
	 */
	@Override
	public void visit_dmul() {
		ts.pop(BasicType.Double);
		ts.pop(BasicType.Double);
		ts.push(BasicType.Double);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dneg()
	 */
	@Override
	public void visit_dneg() {
		ts.pop(BasicType.Double);
		ts.push(BasicType.Double);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_drem()
	 */
	@Override
	public void visit_drem() {
		ts.pop(BasicType.Double);
		ts.pop(BasicType.Double);
		ts.push(BasicType.Double);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dreturn()
	 */
	@Override
	public void visit_dreturn() {
		ts.pop(BasicType.Double);
		endBB(false);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dstore(int)
	 */
	@Override
	public void visit_dstore(int index) {
		ts.pop(BasicType.Double);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dsub()
	 */
	@Override
	public void visit_dsub() {
		ts.pop(BasicType.Double);
		ts.pop(BasicType.Double);
		ts.push(BasicType.Double);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup()
	 */
	@Override
	public void visit_dup() {
		BasicType t = ts.pop();
		ts.push(t);
		ts.push(t);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup2()
	 */
	@Override
	public void visit_dup2() {
        BasicType tv1 = ts.pop();
        
        if (tv1.getCategory() == 1) {
            BasicType tv2 = ts.pop();
            
            ts.push(tv2);
            ts.push(tv1);
            ts.push(tv2);
            ts.push(tv1);            
        } else {
            ts.push(tv1);
            ts.push(tv1);                        
        }
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup2_x1()
	 */
	@Override
	public void visit_dup2_x1() {
        final BasicType tv1 = ts.pop();
        final BasicType tv2 = ts.pop();
        if (tv1.getCategory() == 1) {
            final BasicType tv3 = ts.pop();
            ts.push(tv2);
            ts.push(tv1);
            ts.push(tv3);
            ts.push(tv2);
            ts.push(tv1);            
        } else {
            ts.push(tv1);
            ts.push(tv2);
            ts.push(tv1);                        
        }
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup2_x2()
	 */
	@Override
	public void visit_dup2_x2() {
        final BasicType tv1 = ts.pop();
        final BasicType tv2 = ts.pop();
        
        final int cat1 = tv1.getCategory();
        final int cat2 = tv2.getCategory();
        if ((cat1 == 2) && (cat2 == 2)) {
            // Form 4
            ts.push(tv1);
            ts.push(tv2);
            ts.push(tv1);                                    
        } else {
            final BasicType tv3 = ts.pop();
            final int cat3 = tv3.getCategory();
            if ((cat1 == 1) && (cat2 == 1) && (cat3 == 3)) {
                // Form 3
                ts.push(tv2);
                ts.push(tv1);
                ts.push(tv3);
                ts.push(tv2);
                ts.push(tv1);            
            } else if ((cat1 == 2) && (cat2 == 1) && (cat3 == 1)) {
                // Form 2
                ts.push(tv1);
                ts.push(tv3);
                ts.push(tv2);
                ts.push(tv1);            
            } else {
                // Form 4
                final BasicType tv4 = ts.pop();
                ts.push(tv2);
                ts.push(tv1);
                ts.push(tv4);
                ts.push(tv3);
                ts.push(tv2);
                ts.push(tv1);                            
            }
        }

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup_x1()
	 */
	@Override
	public void visit_dup_x1() {
		final BasicType tv1 = ts.pop();
        final BasicType tv2 = ts.pop();
        ts.push(tv1);
        ts.push(tv2);
        ts.push(tv1);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_dup_x2()
	 */
	@Override
	public void visit_dup_x2() {
        final BasicType tv1 = ts.pop();
        final BasicType tv2 = ts.pop();
        if (tv2.getCategory() == 1) {
            final BasicType tv3 = ts.pop();            
            ts.push(tv1);
            ts.push(tv3);
            ts.push(tv2);
            ts.push(tv1);
        } else {
        	ts.push(tv1);
        	ts.push(tv2);
        	ts.push(tv1);            
        }

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_f2d()
	 */
	@Override
	public void visit_f2d() {
		ts.pop(BasicType.Float);
		ts.push(BasicType.Double);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_f2i()
	 */
	@Override
	public void visit_f2i() {
		ts.pop(BasicType.Float);
		ts.push(BasicType.Int);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_f2l()
	 */
	@Override
	public void visit_f2l() {
		ts.pop(BasicType.Float);
		ts.push(BasicType.Long);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fadd()
	 */
	@Override
	public void visit_fadd() {
		ts.pop(BasicType.Float);
		ts.pop(BasicType.Float);
		ts.push(BasicType.Float);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_faload()
	 */
	@Override
	public void visit_faload() {
		ts.pop(BasicType.Int);
        ts.pop(new ReferenceType(null));
        ts.push(BasicType.Float);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fastore()
	 */
	@Override
	public void visit_fastore() {
		ts.pop(BasicType.Float);
        ts.pop(BasicType.Int);
        ts.pop(new ReferenceType(null));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fcmpg()
	 */
	@Override
	public void visit_fcmpg() {
		ts.pop(BasicType.Float);
		ts.pop(BasicType.Float);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fcmpl()
	 */
	@Override
	public void visit_fcmpl() {
		ts.pop(BasicType.Float);
		ts.pop(BasicType.Float);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fconst(float)
	 */
	@Override
	public void visit_fconst(float value) {
		ts.push(BasicType.Float);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fdiv()
	 */
	@Override
	public void visit_fdiv() {
		ts.pop(BasicType.Float);
		ts.pop(BasicType.Float);
		ts.push(BasicType.Float);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fload(int)
	 */
	@Override
	public void visit_fload(int index) {
		ts.push(BasicType.Float);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fmul()
	 */
	@Override
	public void visit_fmul() {
		ts.pop(BasicType.Float);
		ts.pop(BasicType.Float);
		ts.push(BasicType.Float);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fneg()
	 */
	@Override
	public void visit_fneg() {
		ts.pop(BasicType.Float);
		ts.push(BasicType.Float);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_frem()
	 */
	@Override
	public void visit_frem() {
		ts.pop(BasicType.Float);
		ts.pop(BasicType.Float);
		ts.push(BasicType.Float);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_freturn()
	 */
	@Override
	public void visit_freturn() {
		ts.pop(BasicType.Float);
		endBB(false);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fstore(int)
	 */
	@Override
	public void visit_fstore(int index) {
		ts.pop(BasicType.Float);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_fsub()
	 */
	@Override
	public void visit_fsub() {
		ts.pop(BasicType.Float);
		ts.pop(BasicType.Float);
		ts.push(BasicType.Float);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_getfield(icebird.metadata.constpool.ConstField)
	 */
	@Override
	public void visit_getfield(ConstField fieldRef) {
		ts.pop(new ReferenceType(null));
		ts.push(fieldRef.getType());

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_getstatic(icebird.metadata.constpool.ConstField)
	 */
	@Override
	public void visit_getstatic(ConstField fieldRef) {
		ts.push(fieldRef.getType());
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_goto(int)
	 */
	@Override
	public void visit_goto(int address) {
		addBranch(address, false);
		condYieldPoint(address);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2b()
	 */
	@Override
	public void visit_i2b() {
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2c()
	 */
	@Override
	public void visit_i2c() {
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2d()
	 */
	@Override
	public void visit_i2d() {
		ts.pop(BasicType.Int);
		ts.push(BasicType.Double);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2f()
	 */
	@Override
	public void visit_i2f() {
		ts.pop(BasicType.Int);
		ts.push(BasicType.Float);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2l()
	 */
	@Override
	public void visit_i2l() {
		ts.pop(BasicType.Int);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_i2s()
	 */
	@Override
	public void visit_i2s() {
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iadd()
	 */
	@Override
	public void visit_iadd() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iaload()
	 */
	@Override
	public void visit_iaload() {
		ts.pop(BasicType.Int);
		ts.pop(new ReferenceType(null));
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iand()
	 */
	@Override
	public void visit_iand() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iastore()
	 */
	@Override
	public void visit_iastore() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.pop(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iconst(int)
	 */
	@Override
	public void visit_iconst(int value) {
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_idiv()
	 */
	@Override
	public void visit_idiv() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_acmpeq(int)
	 */
	@Override
	public void visit_if_acmpeq(int address) {
		ts.pop(new ReferenceType(null));
		ts.pop(new ReferenceType(null));
		
		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_acmpne(int)
	 */
	@Override
	public void visit_if_acmpne(int address) {
		ts.pop(new ReferenceType(null));
		ts.pop(new ReferenceType(null));
		
		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmpeq(int)
	 */
	@Override
	public void visit_if_icmpeq(int address) {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		
		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmpge(int)
	 */
	@Override
	public void visit_if_icmpge(int address) {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		
		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmpgt(int)
	 */
	@Override
	public void visit_if_icmpgt(int address) {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		
		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmple(int)
	 */
	@Override
	public void visit_if_icmple(int address) {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		
		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmplt(int)
	 */
	@Override
	public void visit_if_icmplt(int address) {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		
		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_if_icmpne(int)
	 */
	@Override
	public void visit_if_icmpne(int address) {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		
		addBranch(address, true);
		condYieldPoint(address);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifeq(int)
	 */
	@Override
	public void visit_ifeq(int address) {
		ts.pop(BasicType.Int);

		addBranch(address, true);
		condYieldPoint(address);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifge(int)
	 */
	@Override
	public void visit_ifge(int address) {
		ts.pop(BasicType.Int);

		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifgt(int)
	 */
	@Override
	public void visit_ifgt(int address) {
		ts.pop(BasicType.Int);

		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifle(int)
	 */
	@Override
	public void visit_ifle(int address) {
		ts.pop(BasicType.Int);

		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iflt(int)
	 */
	@Override
	public void visit_iflt(int address) {
		ts.pop(BasicType.Int);

		addBranch(address, true);
		condYieldPoint(address);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifne(int)
	 */
	@Override
	public void visit_ifne(int address) {
		ts.pop(BasicType.Int);

		addBranch(address, true);
		condYieldPoint(address);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifnonnull(int)
	 */
	@Override
	public void visit_ifnonnull(int address) {
		ts.pop(new ReferenceType(null));
		
		addBranch(address, true);
		condYieldPoint(address);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ifnull(int)
	 */
	@Override
	public void visit_ifnull(int address) {
		ts.pop(new ReferenceType(null));
		
		addBranch(address, true);
		condYieldPoint(address);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iinc(int, int)
	 */
	@Override
	public void visit_iinc(int index, int incValue) {
		

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iload(int)
	 */
	@Override
	public void visit_iload(int index) {
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_imul()
	 */
	@Override
	public void visit_imul() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ineg()
	 */
	@Override
	public void visit_ineg() {
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_instanceof(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_instanceof(ConstClass clazz) {
		ts.pop(new ReferenceType(null));
		ts.push(BasicType.Int);

	}
	
    private final void popArguments(ConstMethod methodRef) {
    	BasicType[] types = methodRef.getArguments();

        for (int i = types.length-1; i >= 0; i--) {
            ts.pop(types[i]);
        }
    }
    
    private final void pushReturnValue(ConstMethod methodRef) {
    	BasicType type = methodRef.getReturnType();
        
        if (type != BasicType.Void) {
            ts.push(type);
        }
    }

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_invokeinterface(icebird.metadata.constpool.ConstIMethod, int)
	 */
	@Override
	public void visit_invokeinterface(ConstIMethod methodRef, int count) {
		popArguments(methodRef);
		ts.pop(new ReferenceType(null));
		pushReturnValue(methodRef);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_invokespecial(icebird.metadata.constpool.ConstMethod)
	 */
	@Override
	public void visit_invokespecial(ConstMethod methodRef) {
		popArguments(methodRef);
		ts.pop(new ReferenceType(null));
		pushReturnValue(methodRef);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_invokestatic(icebird.metadata.constpool.ConstMethod)
	 */
	@Override
	public void visit_invokestatic(ConstMethod methodRef) {
		popArguments(methodRef);
		pushReturnValue(methodRef);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_invokevirtual(icebird.metadata.constpool.ConstMethod)
	 */
	@Override
	public void visit_invokevirtual(ConstMethod methodRef) {
		popArguments(methodRef);
		ts.pop(new ReferenceType(null));
		pushReturnValue(methodRef);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ior()
	 */
	@Override
	public void visit_ior() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_irem()
	 */
	@Override
	public void visit_irem() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ireturn()
	 */
	@Override
	public void visit_ireturn() {
		ts.pop(BasicType.Int);
		endBB(false);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ishl()
	 */
	@Override
	public void visit_ishl() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ishr()
	 */
	@Override
	public void visit_ishr() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_istore(int)
	 */
	@Override
	public void visit_istore(int index) {
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_isub()
	 */
	@Override
	public void visit_isub() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_iushr()
	 */
	@Override
	public void visit_iushr() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ixor()
	 */
	@Override
	public void visit_ixor() {
		ts.pop(BasicType.Int);
		ts.pop(BasicType.Int);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_jsr(int)
	 */
	@Override
	public void visit_jsr(int address, int ret) {
		ts.push(BasicType.ReturnAddress);
		
		addBranch(address, false);
		condYieldPoint(address);
		
		ts.pop();
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_l2d()
	 */
	@Override
	public void visit_l2d() {
		ts.pop(BasicType.Long);
		ts.push(BasicType.Double);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_l2f()
	 */
	@Override
	public void visit_l2f() {
		ts.pop(BasicType.Long);
		ts.push(BasicType.Float);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_l2i()
	 */
	@Override
	public void visit_l2i() {
		ts.pop(BasicType.Long);
		ts.push(BasicType.Int);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ladd()
	 */
	@Override
	public void visit_ladd() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_laload()
	 */
	@Override
	public void visit_laload() {
		ts.pop(BasicType.Int);
		ts.pop(new ReferenceType(null));
		ts.push(BasicType.Long);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_land()
	 */
	@Override
	public void visit_land() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lastore()
	 */
	@Override
	public void visit_lastore() {
		ts.pop(BasicType.Long);
        ts.pop(BasicType.Int);
        ts.pop(new ReferenceType(null));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lcmp()
	 */
	@Override
	public void visit_lcmp() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lconst(long)
	 */
	@Override
	public void visit_lconst(long value) {
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ldc(java.lang.String)
	 */
	@Override
	public void visit_ldc(String value) {
		ts.push(new ReferenceType("java/lang/String"));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ldc(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_ldc(ConstClass value) {
		ts.push(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ldiv()
	 */
	@Override
	public void visit_ldiv() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lload(int)
	 */
	@Override
	public void visit_lload(int index) {
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lmul()
	 */
	@Override
	public void visit_lmul() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lneg()
	 */
	@Override
	public void visit_lneg() {
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lookupswitch(int, int[], int[])
	 */
	@Override
	public void visit_lookupswitch(int defValue, int[] matchValues,
			int[] addresses) {
	    ts.pop(BasicType.Int);
		for (int i = 0; i < addresses.length; i++) {
			addBranch(addresses[i], true);
			condYieldPoint(addresses[i]);
		}
		addBranch(defValue, false);
		condYieldPoint(defValue);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lor()
	 */
	@Override
	public void visit_lor() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lrem()
	 */
	@Override
	public void visit_lrem() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lreturn()
	 */
	@Override
	public void visit_lreturn() {
		ts.pop(BasicType.Long);
		endBB(false);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lshl()
	 */
	@Override
	public void visit_lshl() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lshr()
	 */
	@Override
	public void visit_lshr() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lstore(int)
	 */
	@Override
	public void visit_lstore(int index) {
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lsub()
	 */
	@Override
	public void visit_lsub() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lushr()
	 */
	@Override
	public void visit_lushr() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_lxor()
	 */
	@Override
	public void visit_lxor() {
		ts.pop(BasicType.Long);
		ts.pop(BasicType.Long);
		ts.push(BasicType.Long);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_monitorenter()
	 */
	@Override
	public void visit_monitorenter() {
		ts.pop(new ReferenceType(null));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_monitorexit()
	 */
	@Override
	public void visit_monitorexit() {
		ts.pop(new ReferenceType(null));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_multianewarray(icebird.metadata.constpool.ConstClass, int)
	 */
	@Override
	public void visit_multianewarray(ConstClass clazz, int dimensions) {
		for (int i = 0; i < dimensions; i++) {
			ts.pop(BasicType.Int);
        }
		ts.push(new ReferenceType(null));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_new(icebird.metadata.constpool.ConstClass)
	 */
	@Override
	public void visit_new(ConstClass clazz) {
		ts.push(new ReferenceType(clazz.getName()));

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_newarray(int)
	 */
	@Override
	public void visit_newarray(int type) {
		ts.pop(BasicType.Int);
		ts.push(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_nop()
	 */
	@Override
	public void visit_nop() {

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_pop()
	 */
	@Override
	public void visit_pop() {
		ts.pop();

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_pop2()
	 */
	@Override
	public void visit_pop2() {
		BasicType t = ts.pop();
		if (t.getCategory() == 1) {
			ts.pop();
		}
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_putfield(icebird.metadata.constpool.ConstField)
	 */
	@Override
	public void visit_putfield(ConstField fieldRef) {
		ts.pop(new ReferenceType(null));
		ts.pop(fieldRef.getType());

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_putstatic(icebird.metadata.constpool.ConstField)
	 */
	@Override
	public void visit_putstatic(ConstField fieldRef) {
		ts.pop(fieldRef.getType());
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_ret(int)
	 */
	@Override
	public void visit_ret(int index) {
		endBB(false);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_return()
	 */
	@Override
	public void visit_return() {
		endBB(false);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_saload()
	 */
	@Override
	public void visit_saload() {
		ts.pop(BasicType.Int);
        ts.pop(new ReferenceType(null));
        ts.push(BasicType.Int);

	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_sastore()
	 */
	@Override
	public void visit_sastore() {
		ts.pop(BasicType.Int);
        ts.pop(BasicType.Int);
        ts.pop(new ReferenceType(null));
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_swap()
	 */
	@Override
	public void visit_swap() {
		final BasicType tv1 = ts.pop();
        final BasicType tv2 = ts.pop();
        ts.push(tv1);
        ts.push(tv2);
	}

	/* (non-Javadoc)
	 * @see icebird.compiler.bytecode.BytecodeVisitor#visit_tableswitch(int, int, int, int[])
	 */
	@Override
	public void visit_tableswitch(int defValue, int lowValue, int highValue,
			int[] addresses) {
	    ts.pop(BasicType.Int);
		for (int i = 0; i < addresses.length; i++) {
			addBranch(addresses[i], true);
			condYieldPoint(addresses[i]);
		}
		addBranch(defValue, false);
		condYieldPoint(defValue);
	}
	
	private void startBB(int pc, boolean sts, TypeStack ts) {
		if ((opcodeFlags[pc] & BASIC_BLOCK) == 0) { 
			opcodeFlags[pc] |= BASIC_BLOCK;
			
			BasicBlock bb = new BasicBlock(pc);
			blocks.put(new Integer(pc), bb);
			if (sts) {
				bb.addEntry(bb);
				bb.setEntryStack(new TypeStack(ts));
			}
		} else if (sts) {
			BasicBlock abb = blocks.get(new Integer(pc));
			TypeStack tst = abb.getEntryStack();
			
			if (tst == null) {
				abb.setEntryStack(ts);
			}
			
			abb.addEntry(current);
		}
	}
	
	private final boolean isStartOfBB(int address) {
		return ((opcodeFlags[address] & BASIC_BLOCK) != 0);
	}

	private final boolean isStartOfException(int address) {
		return ((opcodeFlags[address] & EXCEPTIONHANDLER) != 0);
	}
	
	private final void startException(int address, TypeStack tstack) {	    
		opcodeFlags[address] |= EXCEPTIONHANDLER;
		startBB(address, true, tstack);
	}
	
	private final void startTryBlock(int address) {
		opcodeFlags[address] |= TRYBLOCK;
	}
	
	private final void startTryBlockEnd(int address) {
		opcodeFlags[address] |= TRYBLOCKEND;
	}
	
	private final void condYieldPoint(int target) {
		if (target < address) {
			opcodeFlags[address] |= YEILDPOINT;
		}
	}
	
	private final void endBB(boolean nextFollowsTypeStack) {
		nextBB = true;
		nextTS = nextFollowsTypeStack;
	}
	
	private final void addBranch(int target, boolean conditional) {
		startBB(target, true, ts);
		endBB(conditional);
	}
}
